use crate::START_TS;
use prometheus::{
    register_int_counter, register_int_gauge, Encoder, IntCounter, IntGauge, Opts, TextEncoder,
};
use salvo::{async_trait, handler, Depot, FlowCtrl, Handler, Request, Response};
use std::sync::LazyLock;
use std::time::{SystemTime, UNIX_EPOCH};
use visit_dd_core::APP_ID;
use visit_dd_db::{model_db, user_db};

pub struct PrometheusFilter;

impl PrometheusFilter {
    pub fn new() -> Self {
        Self
    }
}

#[async_trait]
impl Handler for PrometheusFilter {
    async fn handle(
        &self,
        req: &mut Request,
        depot: &mut Depot,
        res: &mut Response,
        ctrl: &mut FlowCtrl,
    ) {
        REQUEST_COUNTER.inc();
        ctrl.call_next(req, depot, res).await;
    }
}

pub static UP_GAUGE: LazyLock<IntGauge> = LazyLock::new(|| {
    let mut opts = Opts::new("up".to_string(), "系统存活秒数".to_string());
    opts.namespace = APP_ID.to_string();
    register_int_gauge!(opts).unwrap()
});
pub static USER_COUNT_GAUGE: LazyLock<IntGauge> = LazyLock::new(|| {
    let mut opts = Opts::new("user_count".to_string(), "平台用户数".to_string());
    opts.namespace = APP_ID.to_string();
    register_int_gauge!(opts).unwrap()
});
pub static MODEL_COUNT_GAUGE: LazyLock<IntGauge> = LazyLock::new(|| {
    let mut opts = Opts::new("model_count".to_string(), "平台模型数".to_string());
    opts.namespace = APP_ID.to_string();
    register_int_gauge!(opts).unwrap()
});
pub static REQUEST_COUNTER: LazyLock<IntCounter> = LazyLock::new(|| {
    let mut opts = Opts::new("requests".to_string(), "包含所有api的请求计数".to_string());
    opts.namespace = APP_ID.to_string();
    register_int_counter!(opts).unwrap()
});

/// 刷新系统活动时长
pub(crate) fn refresh_up() -> u64 {
    let sts = &START_TS.to_owned();
    // println!("{:?}",sts);
    // 直接用两个systemtime做运算似乎有问题，待进一步研究
    let up = SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .unwrap()
        .as_secs()
        - sts;
    // println!("{}",up);
    UP_GAUGE.set(up as i64);
    up
}

#[handler]
pub(crate) async fn g_prometheus(res: &mut Response) {
    refresh_up();
    let uc = user_db::u_count_all().await;
    USER_COUNT_GAUGE.set(uc as i64);
    let mc = model_db::m_count_all().await;
    MODEL_COUNT_GAUGE.set(mc as i64);
    let mut buffer = Vec::new();
    let encoder = TextEncoder::new();
    let metric_families = prometheus::gather();
    encoder.encode(&metric_families, &mut buffer).unwrap();
    let output = String::from_utf8(buffer.clone()).unwrap();
    res.render(output);
}
